﻿using Fleck;
using System.Text;

namespace RFIDStation.DeviceDriver;

public partial class ViewModel
{
    private readonly ILogger _logger;
    private readonly Core.AppConfig _appConfig;
    private readonly List<IWebSocketConnection> _webSocketClientList;
    private readonly Services.AudioService _audioService;

    //private readonly List<Dtos.RegisterRFIDDto> _rfidRegisterList;

    private readonly List<Dtos.RFIDUHFTagDto> _rfidUHFTagList;
    private Dev.Integration.UHFReader.IApiClient _rfidUHFReader;

    private readonly List<Dtos.RFIDHFTagDto> _rfidHFTagList;
    private Dev.Integration.HFReader.IApiClient _rfidHFReader;

    private readonly Dev.Integration.HFReader.IApiClient _cardReader;

    private readonly Dev.Integration.Scanner.IApiClient _scanner;

    public ViewModel( ILoggerFactory loggerFactory, IConfiguration configuration, Services.AudioService audioService )
    {
        _logger = loggerFactory.CreateLogger( nameof( ViewModel ) );

        _appConfig = configuration.Get<Core.AppConfig>( );
        _appConfig.RFIDReaderList = configuration.GetSection( "RFIDReaderList" ).GetChildren( ).Select( i => i.Get<Core.RFIDReaderConfig>( ) ).ToList( );

        _audioService = audioService;

        _webSocketClientList = new( );

        //_rfidRegisterList = new( );

        _rfidUHFTagList = new( );
        _rfidHFTagList = new( );



        _cardReader = new Dev.Integration.HFReader.ApiClientBuilder( )
                                                  .UseReaderKind( _appConfig.CardReader.Kind )
                                                  .UseReaderConfig( o =>
                                                  {
                                                      o.Connect.ConnectType = _appConfig.CardReader.ConnectType;
                                                      o.Connect.ConnectArgs = _appConfig.CardReader.ConnectArgs;
#if DEBUG
                                                      o.MonitorLogAction = log => ConsoleWirter.Debug( $"+ [card reader] {log}" );
#endif
                                                  } )
                                                  .Build( );

        _scanner = new Dev.Integration.Scanner.ApiClientBuilder( )
                                              .UseKind( _appConfig.Scaner.Kind )
                                              .UseConfig( o =>
                                              {
                                                  o.Connect.ConnectType = _appConfig.Scaner.ConnectType;
                                                  o.Connect.ConnectArgs = _appConfig.Scaner.ConnectArgs;
                                                  //#if DEBUG
                                                  o.MonitorLogAction = log => ConsoleWirter.Debug( $"+ [scanner] {log}" );
                                                  //#endif
                                              } )
                                              .Build( );
    }

    public Core.AppConfig AppConfig => _appConfig;
    public Services.AudioService AudioService => _audioService;
    public List<IWebSocketConnection> WebSocketClientList => _webSocketClientList;

    //public List<Dtos.RegisterRFIDDto> RFIDRegisterList => _rfidRegisterList;

    public List<Dtos.RFIDUHFTagDto> RFIDUHFTagList => _rfidUHFTagList;
    public Dev.Integration.UHFReader.IApiClient RFIDUHFReader
    {
        get { return _rfidUHFReader; }
        set { _rfidUHFReader = value; }
    }

    public List<Dtos.RFIDHFTagDto> RFIDHFTagList => _rfidHFTagList;
    public Dev.Integration.HFReader.IApiClient RFIDHFReader
    {
        get { return _rfidHFReader; }
        set { _rfidHFReader = value; }
    }

    public Dev.Integration.HFReader.IApiClient CardReader => _cardReader;

    public Dev.Integration.Scanner.IApiClient Scanner => _scanner;
}

partial class ViewModel
{
    internal void WebSocketClientNotify( Dtos.MsgDto msg, string? client = null )
    {
        var data = msg.ToJson( );

        var query = _webSocketClientList.Where( i => i.IsAvailable );
        if ( client.HasValue( ) )
        {
            query = query.Where( i => i.ConnectionInfo.ClientIpAddress == client );
        }

        var invalidClientList = query.ToList( );
        invalidClientList.ForEach( i =>
        {
            i.Send( data );
        } );

        _logger.Debug( $"发布消息: {data}" );
    }
}

partial class ViewModel
{
    internal void ClearRFIDUHFTags( ) => _rfidUHFTagList.Clear( );

    internal void AddOrUpdateRFIDUHFTag( Dev.Integration.UHFReader.TagInfo tag )
    {
        var find = _rfidUHFTagList.SingleOrDefault( i => i.Id == tag.Id );
        if ( find is null )
        {
            find = new Dtos.RFIDUHFTagDto
            {
                Id = tag.Id,
                Reader = tag.Reader,
                EPC = tag.EPC,
                TID = tag.TID,
                PC = tag.PC,
                AntList = new List<Dtos.RFIDUHFTagDto.AntInfo>
                {
                    new Dtos.RFIDUHFTagDto.AntInfo { AntNo = tag.AntNo, RSSI = tag.RSSI, Count = 1 }
                }
            };

            _rfidUHFTagList.Add( find );
        }
        else
        {
            var findAnt = find.AntList.SingleOrDefault( i => i.AntNo == tag.AntNo );
            if ( findAnt is null )
            {
                find.AntList.Add( new Dtos.RFIDUHFTagDto.AntInfo { AntNo = tag.AntNo, RSSI = tag.RSSI, Count = 1 } );
            }
            else
            {
                findAnt.AntNo = tag.AntNo;
                findAnt.RSSI = tag.RSSI;
                findAnt.Count += 1;
            }
        }
    }

    internal List<Dtos.RFIDUHFTagDto> RFIDUHFInventoryScan( int scanCount, bool includeTID )
    {
        this.ClearRFIDUHFTags( );

        _rfidUHFReader.InventoryScan( o =>
        {
            o.AntNoList = new byte[] { 1 };
            o.ScanCount = scanCount;
            o.IncludeTID = includeTID;
        } );

        return _rfidUHFTagList;
    }

    internal Dtos.KeyValueDto RFIDUHFWriteData( string wirteEPC, string maskEPC = "", bool audio = false )
    {
        try
        {
            if ( _rfidUHFReader is null || _rfidUHFReader.ReaderState == Dev.Integration.UHFReader.Constants.ReaderState.Close ) throw new ArgumentException( $"读写器未启用" );
            if ( wirteEPC.IsNullOrWhiteSpace( ) ) throw new ArgumentException( $"缺少待写入的数据" );

            // 读标签 → 写标签
            {
                if ( maskEPC.IsNullOrWhiteSpace( ) )
                {
                    var readList = _rfidUHFReader.InventoryScan( o => o.ScanCount = 2 );
                    if ( readList.IsNullOrEmpty( ) ) throw new ArgumentException( $"未检测到标签" );
                    if ( readList.Count > 1 ) throw new ArgumentException( $"检测到多张标签. 数量: {readList.Count}" );

                    maskEPC = readList.First( ).EPC;

                    Task.Delay( 200 ).Wait( );
                    _rfidUHFReader.WriteData( o => o.Data = wirteEPC );
                }
                else
                {
                    _rfidUHFReader.WriteData( o =>
                    {
                        o.Data = wirteEPC;
                        o.MaskEPC = maskEPC;
                    } );
                }
            }

            // 发卡成功: 写文件
            {
                var file = Path.Combine( AppDomain.CurrentDomain.BaseDirectory, $"rfid_success_{DateTime.Now.ToString( "yyyyMMdd" )}.txt" );

                var content = $"{maskEPC} → {wirteEPC}{Environment.NewLine}";
                File.AppendAllText( file, content, Encoding.UTF8 );
            }

            // 发卡成功: 提示
            {
                ConsoleWirter.Success( $"写标签成功. {wirteEPC}" );
                _audioService.Ready( file: $"resources/raw/success.wav" );
                if ( audio ) _audioService.Play( );
            }

            return new Dtos.KeyValueDto
            {
                Key = maskEPC,
                Value = wirteEPC,
            };
        }
        catch ( Exception ex )
        {
            _logger.Error( $"写标签失败. {wirteEPC}, error: {ex.Message}" );
            _audioService.Ready( file: $"resources/raw/error.wav" );
            if ( audio ) _audioService.Play( );

            throw ex;
        }
    }

    //internal void RFIDUHFRegister( string data, bool audio, out string epc )
    //{
    //    try
    //    {
    //        if ( _rfidUHFReader is null || _rfidUHFReader.ReaderState == Dev.Integration.UHFReader.Constants.ReaderState.Close ) throw new ArgumentException( $"读写器未启用" );
    //        if ( data.IsNullOrWhiteSpace( ) ) throw new ArgumentException( $"缺少待写入的数据" );

    //        var readyEPC = this.BuildRFIDTagData( data );

    //        // 读标签 → 已发卡检测 → 写标签
    //        {
    //            var readList = _rfidUHFReader.InventoryScan( o => o.ScanCount = 2 );
    //            if ( readList.IsNullOrEmpty( ) ) throw new ArgumentException( $"未检测到标签" );
    //            if ( readList.Count > 1 ) throw new ArgumentException( $"检测到多张标签. 数量: {readList.Count}" );

    //            var readEPC = readList.First( ).EPC;

    //            var any = _rfidRegisterList.Any( i => i.RFID == readEPC );
    //            if ( any ) throw new InvalidOperationException( $"标签[{readEPC}]已发卡. 数据: {data}" );

    //            Task.Delay( 200 ).Wait( );
    //            _rfidUHFReader.WriteData( o => o.Data = readyEPC );
    //        }

    //        // 发卡成功: 写文件
    //        {
    //            var file = Path.Combine( AppDomain.CurrentDomain.BaseDirectory, $"rfid_success_{DateTime.Now.ToString( "yyyyMMdd" )}.txt" );

    //            var content = $"{data},{readyEPC}{Environment.NewLine}";
    //            File.AppendAllText( file, content, Encoding.UTF8 );
    //        }

    //        // 发卡成功: 提示
    //        {
    //            _rfidRegisterList.Add( new Dtos.RegisterRFIDDto { RFID = readyEPC, Data = data } );

    //            ConsoleWirter.Success( $"注册成功. {data} → {readyEPC}" );
    //            _audioService.Ready( file: $"resources/raw/success.wav" );
    //            if ( audio ) _audioService.Play( );
    //        }

    //        epc = readyEPC;
    //    }
    //    catch ( Exception ex )
    //    {
    //        _logger.Error( $"注册失败. {data}, error: {ex.Message}" );
    //        _audioService.Ready( file: $"resources/raw/error.wav" );
    //        if ( audio ) _audioService.Play( );

    //        throw ex;
    //    }
    //}
    //internal string BuildRFIDTagData( string data )
    //{
    //    var len = data.Length;
    //    if ( len > 12 ) throw new ArgumentException( $"数据长度超限: {data}" );

    //    var buffer = ( len % 2 == 1 ? $"{data}F" : data ).HexToBytes( );
    //    var crc = buffer.CRC8( );

    //    var random = Random.Shared.Next( 0, 0xFFFFFF );
    //    var safe = 0x07;    // 默认: 开启

    //    return $"{len.ToString( "D2" )}{data.PadRight( 12, '0' )}{crc.ToString( "X2" )}{random.ToString( "X6" )}{safe.ToString( "X2" )}";
    //}

    //internal bool VerifyRFIDUHFTagData( string epc )
    //{
    //    try
    //    {
    //        var index = 0;

    //        var len = epc.Substring( index, 2 ).ToIntOrDefault( );
    //        index += 2;

    //        var no = epc.Substring( index, 12 );
    //        index += 12;

    //        var crc = byte.Parse( epc.Substring( index, 2 ), System.Globalization.NumberStyles.HexNumber );
    //        index += 2;

    //        var random = epc.Substring( index, 6 );
    //        index += 2;

    //        var safe = epc.Substring( index, 2 );
    //        index += 2;

    //        no = no.Substring( 0, len );    // 实际长度
    //        var buffer = ( no.Length % 2 == 1 ? no = $"{no}F" : no ).HexToBytes( );
    //        var checkCRC = buffer.CRC8( );

    //        var success = crc == checkCRC;
    //        if ( success is false ) throw new Exception( $"非法标签: {epc}" );

    //        return true;
    //    }
    //    catch ( Exception ex )
    //    {
    //        _logger.Error( $"非法标签. {epc}, {ex.Message}" );
    //        return false;
    //    }
    //}
    //internal void RFIDUHFEASSet( string epc, bool enable, out string newEPC )
    //{
    //    var success = this.VerifyRFIDUHFTagData( epc );
    //    if ( success is false ) throw new InvalidOperationException( $"标签校验失败: {epc}" );

    //    var eas = enable ? "07" : "C2";
    //    var epc2 = $"{epc.Substring( 0, epc.Length - 2 )}{eas}";

    //    _rfidUHFReader.WriteData( o =>
    //    {
    //        o.MemoryBank = "epc";
    //        o.Data = epc2;
    //        o.MaskEPC = epc;
    //    } );

    //    newEPC = epc2;
    //}
}

partial class ViewModel
{
    internal void ClearRFIDHFTags( ) => _rfidHFTagList.Clear( );

    internal void AddOrUpdateRFIDHFTag( Dev.Integration.HFReader.TagInfo tag )
    {
        var find = _rfidHFTagList.SingleOrDefault( i => i.UID == tag.UID );
        if ( find is null )
        {
            find = new Dtos.RFIDHFTagDto
            {
                Reader = tag.ReaderId,
                UID = tag.UID,
                BlockData = tag.BlockData,
                AntList = new List<Dtos.RFIDHFTagDto.AntInfo>
                {
                    new Dtos.RFIDHFTagDto.AntInfo { AntNo = tag.AntAddr, Count = 1 }
                }
            };

            _rfidHFTagList.Add( find );
        }
        else
        {
            var findAnt = find.AntList.SingleOrDefault( i => i.AntNo == tag.AntAddr );
            if ( findAnt is null )
            {
                find.AntList.Add( new Dtos.RFIDHFTagDto.AntInfo { AntNo = tag.AntAddr, Count = 1 } );
            }
            else
            {
                findAnt.Count += 1;
            }
        }
    }

    internal List<Dtos.RFIDHFTagDto> RFIDHFInventoryScan( int scanCount, bool readBlock, int blockStartIndex, int blockCount )
    {
        this.ClearRFIDHFTags( );

        var list = _rfidHFReader.InventoryScan( o =>
        {
            o.AntNoList = new byte[] { 1 };
            o.ScanCount = scanCount;
            o.ReadBlock = readBlock;
            o.BlockStartIndex = blockStartIndex;
            o.BlockCount = blockCount;
        } );

        list.ForEach( tag => this.AddOrUpdateRFIDHFTag( tag ) );

        return _rfidHFTagList;
    }

    internal Dtos.KeyValueDto RFIDHFReadBlock( string uid, int blockStartIndex, int blockCount )
    {
        if ( uid.IsNullOrWhiteSpace( ) )
        {
            var tagInfo = _rfidHFReader.Inventory( );
            uid = tagInfo.UID;
        }

        var blockList = _rfidHFReader.ReadMulitBlock( uid, blockStartIndex, blockCount );

        return new Dtos.KeyValueDto
        {
            Key = uid,
            Value = string.Join( string.Empty, blockList.Select( i => i.BlockData ) ),
        };
    }

    internal Dtos.KeyValueDto RFIDHFWriteBlock( string uid, int blockStartIndex, string data )
    {
        if ( uid.IsNullOrWhiteSpace( ) )
        {
            var tagInfo = _rfidHFReader.Inventory( );
            uid = tagInfo.UID;
        }

        _rfidHFReader.WriteMulitBlock( uid, start: blockStartIndex, data );

        return new Dtos.KeyValueDto
        {
            Key = uid,
            Value = data
        };
    }

    internal Dtos.KeyValueDto RFIDHFWirteEAS( string uid, bool enable )
    {
        if ( uid.IsNullOrWhiteSpace( ) )
        {
            var tagInfo = _rfidHFReader.Inventory( );
            uid = tagInfo.UID;
        }

        _rfidHFReader.WriteEAS( uid, enable );

        return new Dtos.KeyValueDto
        {
            Key = uid,
            Value = $"{enable}",
        };
    }

    internal Dtos.KeyValueDto RFIDHFWirteAFI( string uid, byte afi )
    {
        if ( uid.IsNullOrWhiteSpace( ) )
        {
            var tagInfo = _rfidHFReader.Inventory( );
            uid = tagInfo.UID;
        }

        _rfidHFReader.WriteAFI( uid, afi );

        return new Dtos.KeyValueDto
        {
            Key = uid,
            Value = $"{afi:X2}",
        };
    }
}


partial class ViewModel
{
    internal void M1Register( string data, bool audio, out string uid, out int blockNo, out string blockData )
    {
        try
        {
            if ( _cardReader is null ) throw new ArgumentException( $"发卡器未启用" );
            if ( data.IsNullOrWhiteSpace( ) ) throw new ArgumentException( $"缺少待写入数据" );

            blockNo = 4;
            blockData = this.BuildReaderTagData( data );

            // 读标签
            var tagInfo = _cardReader.M1Inventory( );
            uid = tagInfo.UID;

            // 写数据块
            _cardReader.M1WriteBlock( blockNo, blockData );

            // 发卡成功: 写文件
            {
                var file = Path.Combine( AppDomain.CurrentDomain.BaseDirectory, $"m1_success_{DateTime.Now.ToString( "yyyyMMdd" )}.txt" );

                var content = $"{blockData},{data}{Environment.NewLine}";
                File.AppendAllText( file, content, Encoding.UTF8 );
            }

            // 发卡成功: 提示
            {
                ConsoleWirter.Success( $"注册成功. {data} → {blockData}" );

                _audioService.Ready( file: $"resources/raw/success.wav" );
                if ( audio ) _audioService.Play( );
            }
        }
        catch ( Exception ex )
        {
            _logger.Error( $"注册失败. {data}, error: {ex.Message}" );
            _audioService.Ready( file: $"resources/raw/error.wav" );
            if ( audio ) _audioService.Play( );

            throw ex;
        }
    }
    internal string BuildReaderTagData( string data )
    {
        var len = data.Length;
        if ( len > 32 ) throw new ArgumentException( $"数据长度超限: {data}" );

        return $"{len.ToString( "D2" )}{data.PadRight( 30, '0' )}";
    }
}


partial class ViewModel
{
    //internal void TestRFIDUHFReader( int loop )
    //{
    //    int success = 0, error = 0;

    //    _ = Task.Factory.StartNew( ( ) =>
    //    {
    //        for ( int i = 1; i <= loop; i++ )
    //        {
    //            ConsoleWirter.Info( $"超高频读写器 第{i}/{loop}轮测试..." );
    //            Thread.Sleep( 1000 );

    //            var data = i.ToString( "D4" );

    //            try
    //            {
    //                this.RFIDUHFRegister( data, audio: true, out var epc );
    //                success += 1;
    //            }
    //            catch
    //            {
    //                error += 1;
    //            }

    //            _rfidRegisterList.Clear( );
    //        }

    //        ConsoleWirter.Success( $"成功: {success}/{loop} = {( (decimal)success / (decimal)loop ).ToString( "P" )}" );
    //        ConsoleWirter.Warning( $"失败: {error}/{loop} = {( (decimal)error / (decimal)loop ).ToString( "P" )}" );
    //    } );
    //}

}

